#pragma once
#include <cpr/response.h>
#include <elasticlient/client.h>
#include <iostream>
#include <json/json.h>
#include <sstream>

#include "esearch.hpp"
#include "user.hxx"
#include "message.hxx"

namespace im
{
    class ESClientFactory {
    public:
        static std::shared_ptr<elasticlient::Client> create(const std::vector<std::string> host_list) {
            return std::make_shared<elasticlient::Client>(host_list);
        }
    };
    class ESUser{
    public:
        using ptr = std::shared_ptr<ESUser>;
        ESUser(const std::shared_ptr<elasticlient::Client>& client): _es_client(client){}

        bool createIndex(){
            bool ret = ESIndex(_es_client, "user")
                            .append("user_id", "keyword", "standard", true)
                            .append("nickname")
                            .append("phone", "keyword", "standard", true)
                            .append("description", "keyword", "standard", false)
                            .append("avatar_id", "keyword", "standard", false)
                            .create();
            if (ret == false) {
                LOG_CRITICAL("用户信息索引创建失败!");
                return false;
            }
            LOG_INFO("用户信息索引创建成功!");
            return true;
        }

        bool appendData(const std::string &uid,
                const std::string &phone,
                const std::string &nickname,
                const std::string &description,
                const std::string &avatar_id){
            bool ret = ESInsert(_es_client, "user")
                                .append("user_id", uid)
                                .append("nickname", nickname)
                                .append("phone", phone)
                                .append("description", description)
                                .append("avatar_id", avatar_id)
                                .insert(uid);
            if (ret == false) {
                LOG_CRITICAL("用户数据插入/更新失败!");
                return false;
            }
            LOG_INFO("用户数据新增/更新成功!");
            return true;
        }

        std::vector<User> search(const std::string &key, const std::vector<std::string> &filter_uid_list){
            std::vector<User> res;
            Json::Value json_user = ESSearch(_es_client, "user")
                        .append_should_match("user_id.keyword", key)
                        .append_should_match("phone.keyword", key)
                        .append_should_match("nickname", key)
                        .append_must_not_terms("user_id.keyword", filter_uid_list)
                        .search();
            if (json_user.isArray() == false) {
                LOG_CRITICAL("用户搜索结果为空，或者结果不是数组类型");
                return res;
            }

            for(auto& u : json_user){
                User user;
                user.user_id(u["_source"]["user_id"].asString()); 
                user.user_name(u["_source"]["nickname"].asString()); 
                user.description(u["_source"]["description"].asString()); 
                user.phone(u["_source"]["phone"].asString()); 
                user.avatar_id(u["_source"]["avatar_id"].asString()); 
                res.push_back(user);
            }
            return res;
        }

    private:
        std::shared_ptr<elasticlient::Client> _es_client;
    };

    class ESMessage{
    public:
        using ptr = std::shared_ptr<ESMessage>;
        ESMessage(const std::shared_ptr<elasticlient::Client>& client): _es_client(client){}

        bool createIndex(){
            bool ret = ESIndex(_es_client, "message")
                            .append("user_id", "keyword", "standard", false)
                            .append("message_id", "keyword", "standard", false)
                            .append("chat_session_id", "keyword", "standard")
                            .append("content")
                            .append("create_time", "long", "standard", false)
                            .create();
            if(ret == false){
                LOG_INFO("用户信息索引创建失败!");
            }else{
                LOG_INFO("用户信息索引创建成功!");
            }
            return ret;
        }

        bool appendData(
            const std::string &user_id,
            const std::string &message_id,
            const std::string &chat_session_id,
            const std::string &content,
            const long &create_time
        ){
            bool ret = ESInsert(_es_client, "message")
                                .append("user_id", user_id)
                                .append("message_id", message_id)
                                .append("chat_session_id", chat_session_id)
                                .append("content", content)
                                .append("create_time", create_time)
                                .insert(message_id);
            if(ret == false){
                LOG_CRITICAL("用户数据插入/更新失败!");
            }else{
                LOG_INFO("用户数据新增/更新成功!");
            }
            return ret;
        }

        bool remove(const std::string &message_id){
            bool ret = ESRemove(_es_client, "message").remove(message_id);
            if (ret == false) {
                LOG_CRITICAL("用户数据删除失败!");
            }else{
                LOG_INFO("用户数据删除成功!");
            }
            return ret;
        }

        std::vector<Message> search(const std::string &chat_session_id, const std::string &key){
            std::vector<Message> res;
            Json::Value json_user = ESSearch(_es_client, "message")
                                    .append_must_term("chat_session_id.keyword", chat_session_id)
                                    .append_must_match("content", key)
                                    .search();
            if(json_user.isArray() == false){
                LOG_CRITICAL("用户搜索结果为空，或者结果不是数组类型");
            } else{
                int sz = json_user.size();
                LOG_DEBUG("检索结果条目数量：{}", sz);
                for(auto& u : json_user){
                    Message msg;
                    msg.user_id(u["_source"]["user_id"].asString());
                    msg.session_id(u["_source"]["chat_session_id"].asString());
                    msg.message_id(u["_source"]["message_id"].asString());
                    msg.content(u["_source"]["content"].asString());
                    auto ctime = boost::posix_time::from_time_t(u["_source"]["create_time"].asInt64());
                    msg.create_time(ctime);
                    res.push_back(msg);
                }
            }
            return res;
        }
    private:
        std::shared_ptr<elasticlient::Client> _es_client;
    };
} // namespace im
